#include "scan.h"
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "libsocketcan.h"
#include "log/zuclog.h"

#define scan_debug(FMT, ...)  //zuclog_debug("scan", FMT, ##__VA_ARGS__)

using namespace std;
using namespace rtbus;

SCan::SCan() {}
SCan::~SCan() {}

int SCan::load_cfg(SCan::Config& cfg)
{
    is_actived_ = false;
    cfg_ = cfg;
    return 0;
}

int SCan::active()
{
#ifndef _DEBUG
    if (can_do_stop(cfg_.adapter_name.c_str()))
    {
        return -1;
    }
    if (can_set_bitrate(cfg_.adapter_name.c_str(), 1000000))
    {
        return -1;
    }
    if (can_do_start(cfg_.adapter_name.c_str()))
    {
        return -1;
    }
#endif
    if ((fd_ = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
    {
        return -1;
    }
    struct ifreq ifr;
    strncpy(ifr.ifr_name, cfg_.adapter_name.c_str(), sizeof(ifr.ifr_name));
    if (ioctl(fd_, SIOCGIFINDEX, &ifr))
    {
        return -1;
    }

    struct sockaddr_can addr;
    addr.can_family = PF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    if (bind(fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        return -1;
    }
    if (fcntl(fd_, F_SETFL, O_NDELAY))
    {
        return -1;
    }
    is_actived_ = true;
    return 0;
}

int SCan::deactive()
{
    is_actived_ = false;
    close(fd_);
    fd_ = -1;
#ifndef _DEBUG
    can_do_stop(cfg_.adapter_name.c_str());
#endif
    return 0;
}
int SCan::send(FrameData* frame, size_t cnt)
{
    if (!is_actived_)
        return 0;
    int ret = 0;
    for (size_t i = 0; i < cnt; i++)
    {
        struct can_frame msg;
        msg.can_id = frame[i].id;
        msg.can_dlc = frame[i].dlc;
        memcpy(msg.data, frame[i].data, frame[i].dlc);
        if (frame[i].id > 0xffff)
        {
            msg.can_id &= CAN_EFF_MASK;
            msg.can_id |= CAN_EFF_FLAG;
        }
        else
        {
            msg.can_id &= CAN_SFF_MASK;
        }
        scan_debug("send:0x%x %x %x %x %x %x %x %x %x\n",
                   msg.can_id,
                   msg.data[0],
                   msg.data[1],
                   msg.data[2],
                   msg.data[3],
                   msg.data[4],
                   msg.data[5],
                   msg.data[6],
                   msg.data[7]);
        if (write(fd_, &msg, sizeof(struct can_frame)) <= 0)
        {
            break;
        }
        ret++;
    }
    return ret;
}
int SCan::recv(FrameData* data, size_t cnt)
{
    if (!is_actived_)
        return 0;
    struct can_frame msg[200];
    uint32_t ret = 0;
    for (uint32_t i = 0; i < cnt; i++)
    {
        int nbytes = read(fd_, &msg[i], sizeof(struct can_frame));
        if (nbytes < 0)
            break;
        scan_debug("recv:0x%x %x %x %x %x %x %x %x %x\n",
                   msg[i].can_id,
                   msg[i].data[0],
                   msg[i].data[1],
                   msg[i].data[2],
                   msg[i].data[3],
                   msg[i].data[4],
                   msg[i].data[5],
                   msg[i].data[6],
                   msg[i].data[7]);
        ret++;
        data[i].id = msg[i].can_id;
        data[i].id &= CAN_EFF_MASK;
        data[i].id &= CAN_ERR_MASK;
        data[i].dlc = msg[i].can_dlc;
        memcpy(data[i].data, msg[i].data, data[i].dlc);
    }
    return ret;
}